<?php
/**
 * Created by PhpStorm.
 * Script Name: Mp.php
 * Create: 2022/12/22 17:52
 * Description:
 * Author: fudaoji<fdj@kuryun.cn>
 */

namespace plugin\wechat\app\service;
use EasyOpen\Tencent\Request\Mp\WxaModifyDomain;
use EasyOpen\Tencent\Request\Mp\WxaSetWebViewDomain;
use EasyWeChat\Factory;
use plugin\wechat\app\model\Mini as MiniM;
use plugin\wechat\app\service\MiniReg as RegService;
use plugin\wechat\app\service\OpenPlatform as OpenPlatformService;
use Symfony\Component\Cache\Adapter\RedisAdapter;
use Symfony\Component\HttpFoundation\HeaderBag;
use Symfony\Component\HttpFoundation\Request as SymfonyRequest;
use Support\Request;

class Mini extends Common
{
    //0待提交审核 1为， 2为审核成功，3为审核失败，4为已发布, 5:为已撤回 6审核延后
    const STATUS_READY = 0;
    const STATUS_VERIFYING = 1;
    const STATUS_SUCCESS = 2;
    const STATUS_FAIL = 3;
    const STATUS_PUBLISHED = 4;
    const STATUS_CANCEL = 5;
    const STATUS_DELAY = 6;

    /**
     * 注册类型
     * @param null $id
     * @return array|mixed
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public static function registerTypes($id = null){
        $list = [
            0 => '普通方式注册',
            2 => '通过复用公众号创建小程序api注册',
            6 => '人扫脸创建企业小程序api注册',
            13 => '通过创建试用小程序api注册',
            15 => '通过联盟控制台注册',
            16 => '通过创建个人小程序api注册',
            17 => '通过创建个人交易小程序api注册',
            19 => '通过试用小程序转正api注册',
            22 => '通过复用商户号创建企业小程序api注册',
            23 => '通过复用商户号转正api注册'
        ];
        return isset($list[$id]) ? $list[$id] : $list;
    }

    /**
     * 认证类型
     * @param null $id
     * @return array|mixed
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public static function verifyTypes($id = null){
        $list = [
            -1 => '未认证',
            0 => '微信认证'
        ];
        return isset($list[$id]) ? $list[$id] : $list;
    }

    /**
     * 设置webview domain
     * @param array $config
     * @param null $mini_info
     * @return bool|mixed
     * @throws \EasyWeChat\Kernel\Exceptions\HttpException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     * @throws \EasyWeChat\Kernel\Exceptions\RuntimeException
     * @throws \Psr\SimpleCache\InvalidArgumentException Author: fudaoji<fdj@kuryun.cn>
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    static function webViewDomainSet($config = [], $mini_info = null){
        $request = new WxaSetWebViewDomain();
        $request->setAction('set');
        $request->setWebViewDomain($config['webview_domain']);
        $response = self::tencentOpenCli()->execute($request, self::getAccessToken($mini_info));
        if(empty($response['code'])) {
            return $response['errmsg'];
        }
        return true;
    }

    /**
     * 更新安全域名
     * @param array $config
     * @param null $mini_info
     * @return bool|mixed
     * @throws \EasyWeChat\Kernel\Exceptions\HttpException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     * @throws \EasyWeChat\Kernel\Exceptions\RuntimeException
     * @throws \Psr\SimpleCache\InvalidArgumentException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * Author: fudaoji<fdj@kuryun.cn>
     */
    static function domainModify($config = [], $mini_info = null){
        $request = new WxaModifyDomain();
        $request->setAction('set');
        $request_domain = is_string($config['request_domain']) ? explode(';', $config['request_domain']) : $config['request_domain'];
        $socket_domain = is_string($config['socket_domain']) ? explode(';', $config['socket_domain']) : $config['socket_domain'];
        $upload_domain = is_string($config['upload_domain']) ? explode(';', $config['upload_domain']) : $config['upload_domain'];
        $download_domain = is_string($config['download_domain']) ? explode(';', $config['download_domain']) : $config['download_domain'];
        $request->setRequestDomain($request_domain);
        $request->setWsRequestDomain($socket_domain);
        $request->setUploadDomain($upload_domain);
        $request->setDownloadDomain($download_domain);
        $response = self::tencentOpenCli()->execute($request, self::getAccessToken($mini_info));

        if(empty($response['code'])) {
            return $response['errmsg'];
        }
        return true;
    }

    /**
     * @param $mini_info
     * @param Request|null $request
     * @return \EasyWeChat\MiniProgram\Application|\EasyWeChat\OpenPlatform\Authorizer\MiniProgram\Application
     * Author: fudaoji<fdj@kuryun.cn>
     * @throws \Psr\SimpleCache\InvalidArgumentException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    static function getApp($mini_info, Request $request = null){
        is_null($request) && $request = \request();
        $config = [
            'app_id'   => '',
            'secret'   => '',
            'response_type' => 'array',
            'log' => [
                'default' => getenv('APP_DEBUG') ? 'dev' : 'prod' , // 默认使用的 channel，生产环境可以改为下面的 prod
                'channels' => [
                    // 测试环境
                    'dev' => [
                        'driver' => 'single',
                        'path' => runtime_path() . '/logs/wechat/'.$mini_info['appid'].'.log',
                        'level' => 'debug',
                    ],
                    // 生产环境
                    'prod' => [
                        'driver' => 'daily',
                        'path' => runtime_path() . '/logs/wechat/'.$mini_info['appid'].'.log',
                        'level' => 'error',
                        'days' => 3
                    ],
                ],
            ],
        ];
        if($mini_info['appsecret']){
            $config['app_id'] = $mini_info['appid'];
            $config['secret'] = $mini_info['appsecret'];
            $app = Factory::miniProgram($config);
        }else{
            $app = OpenPlatformService::getOpenPlatform()->miniProgram($mini_info['appid'], $mini_info['refresh_token']);
        }

        //rebind cache driver
        $app->rebind('cache', new RedisAdapter(self::deserveRedis()));

        if($request) {
            $symfony_request = new SymfonyRequest($request->get(), $request->post(), [], $request->cookie(), [], [], $request->rawBody());
            $symfony_request->headers = new HeaderBag($request->header());
            $app->rebind('request', $symfony_request);
        }

        return $app;
    }

    /**
     * 获取小程序信息
     * @param string $appid
     * @return array|mixed|\think\db\Query|\think\Model|null
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public static function getInfo($appid = ''){
        return MiniM::where('appid', $appid)
            ->find();
    }

    /**
     * 授权方小程序信息入库
     * @param array $auth_info
     * @param int $company_id
     * @param int $tenant_id
     * @return mixed
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * @author fudaoji<fdj@kuryun.cn>
     */
    static function updateAuthInfo($auth_info, $company_id = 0, $tenant_id = 0) {
        $result = false;
        $authorizer_info = $auth_info['authorizer_info'];
        $insert_data = [
            'appid'             => $auth_info['authorization_info']['authorizer_appid'],
            'refresh_token'     => $auth_info['authorization_info']['authorizer_refresh_token'],
            'nick_name'         => $authorizer_info['nick_name'],
            'head_img'          => $authorizer_info['head_img'] ?? '',
            'service_type_info' => $authorizer_info['service_type_info']['id'],
            'verify_type_info'  => $authorizer_info['verify_type_info']['id'],
            'user_name'         => $authorizer_info['user_name'],
            'principal_name'    => $authorizer_info['principal_name'],
            'alias'             => $authorizer_info['alias'],
            'business_info'     => json_encode($authorizer_info['business_info']),
            'qrcode_url'        => $authorizer_info['qrcode_url'],
            'idc'               => $authorizer_info['idc'],
            'signature'         => $authorizer_info['signature'],
            'func_info'         => json_encode($auth_info['authorization_info']['func_info']),
            'mini_program_info' => json_encode($authorizer_info['MiniProgramInfo']),
            'is_auth'           => 1,
            'account_status' => $authorizer_info['account_status'] ?? 1,
            'register_type' => $authorizer_info['register_type'] ?? 0,
        ];
        //var_dump($insert_data);
        if($mp = self::getInfo($insert_data['appid'])) {
            $insert_data['id'] = $mp['id'];
            $result = MiniM::update($insert_data);
        }elseif($company_id > 0 || in_array($insert_data['appid'], OpenPlatform::testApps()) || ($reg = RegService::getByAppId($insert_data['appid']))) {
            if(!empty($reg)){ //注册试用小程序的
                $company_id = $reg['company_id'];
                $tenant_id = $reg['tenant_id'];
            }
            $insert_data['company_id'] = $company_id;
            $insert_data['tenant_id'] = $tenant_id;
            $result = MiniM::create($insert_data);
        }
        return $result;
    }

    /**
     * 小程序取消授权后
     * @param $mini
     * @throws \think\db\exception\DbException
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public static function cancelAuth($mini)
    {
        MiniM::update(['id' => $mini['id'], 'is_auth' => 0]);
    }

    /**
     * 返回小程序的认证类型
     * @param array $data
     * @return string
     * @author: fudaoji<fdj@kuryun.cn>
     */
    public static function getTypeDesc($data = []){
        return $data['verify_type_info'] == -1 ? '未认证' : '认证';
    }

    /**
     * 获取小程序app的access token
     * @param null $mp_info
     * @param bool $refresh
     * @return mixed
     * @throws \EasyWeChat\Kernel\Exceptions\HttpException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     * @throws \EasyWeChat\Kernel\Exceptions\RuntimeException
     * @throws \Psr\SimpleCache\InvalidArgumentException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public static function getAccessToken($mp_info = null, $refresh = false){
        if($mp_info === null){
            $request = \request();
            $mp_info = $request->miniInfo;
        }
        $app = self::getApp($mp_info);
        $token = $app->access_token->getToken();
        if($refresh || empty($token)){
            $token = $app->access_token->getToken(true);
        }

        if(!empty($token['authorizer_access_token'])){
            return $token['authorizer_access_token']; //授权方式
        }elseif (!empty($token['access_token'])){
            return $token['access_token']; //手动方式
        }
        return '';
    }

    /**
     * 获取当前mp
     * @return mixed
     * Author: fudaoji<fdj@kuryun.cn>
     */
    static function getSessionInfo(){
        return session(CURRENT_MINI);
    }

    /**
     * 设置当前mp
     * @param $data
     * @return mixed
     * Author: fudaoji<fdj@kuryun.cn>
     */
    static function setSessionInfo($data){
        return session([CURRENT_MINI => $data]);
    }
}